import { trigger, track } from './effect';
import { isObject, hasChanged } from './utils';
import { ReactiveFlags, reactive } from './reactive';
import { TrackOpTypes, TriggerOpTypes } from './operations';

// 用来表示对象的"迭代依赖"标识
export const ITERATE_KEY = Symbol('');

function get(target: object, key: string | symbol, receiver: object): any { 
  if (key === ReactiveFlags.IS_REACTIVE) { 
    return true;
  }
  // todo: 收集依赖
  track(target, TrackOpTypes.GET, key);
  // 返回对象的相应属性值
  const result = Reflect.get(target, key, receiver);

  // 如果是对象，再次进行递归代理
  if (isObject(result)) { 
    return reactive(result);
  }

  return result;
}

function set(target: Record<string | symbol, unknown>, key: string | symbol, value: unknown, receiver: object): boolean { 
  // todo: 触发更新
  // 判断动作是ADD还是SET，而且SET操作应该是值不一样的情况下再进行处理
  const hadKey = target.hasOwnProperty(key);

  // ts注意object类型，target[key]如果直接这么写，ts会报错，元素有隐式的any类型
  // 这里可以直接将target修改为Record<string | symbol, unknown>
  let oldValue = target[key];

  if (!hadKey) {
    trigger(target, TriggerOpTypes.ADD, key);
  }
  else if(hasChanged(value, oldValue)) { 
    trigger(target, TriggerOpTypes.SET, key);
  }
  
  // 设置对象的相应属性值
  const result = Reflect.set(target, key, value, receiver);
  return result;
}

function has(target: object, key: string | symbol): boolean { 
  // todo: 收集依赖
  track(target, TrackOpTypes.GET, key);
  const result = Reflect.has(target, key);
  return result;
}

function ownKeys(target: object): (string | symbol)[] { 
  // 依赖收集
  track(target, TrackOpTypes.ITERATE, ITERATE_KEY);
  return Reflect.ownKeys(target);
}

function deleteProperty(target: Record<string | symbol, unknown>, key: string | symbol) { 
  // 删除也判断是否属性存在
  const hadKey = target.hasOwnProperty(key);
  // 删除的结果
  const result = Reflect.deleteProperty(target, key);

  // 对象有这个属性，并且删除成功，触发更新
  if(hadKey && result) { 
    trigger(target, TriggerOpTypes.DELETE, key);
  }
  return result;
}

export const mutableHandlers: ProxyHandler<object> = {
  get,
  set,
  has,
  ownKeys,
  deleteProperty
}